package Lib3d.Animation;


import Lib3d.Vector3d;
import Lib3d.MyUtils.Debug;
import Lib3d.SceneGraph.Node;
import Lib3d.SceneGraph.Impl.RotationImpl;
import Lib3d.SceneGraph.Impl.TranslationImpl;

import java.util.Iterator;

import javax.media.opengl.GLAutoDrawable;

/**
 * A simple animation implementation.
 * 
 * @author Wassim Chegham
 * @version 0.1
 * @category Lib3d.Animation
 * 
 */
public class SimpleAnimationImpl implements Animation {

    private float angle = 0;
    private static float sense = 1;
    private float speed = 0.01f;
    private final float steps = 0.001f;
    private float dist = 100;
    private static boolean canAnimation = false;
    private static Vector3d animationFunction = new Vector3d(0, 0, 0);
    private final TranslationImpl translation;
    private final RotationImpl rotation;

    public SimpleAnimationImpl() {
        this.translation = new TranslationImpl(new Vector3d(0, 0, 0));
        this.rotation = new RotationImpl(new Vector3d(1, 0, 0), 0);
    }

    public SimpleAnimationImpl(final Vector3d translation) {
        this.translation = new TranslationImpl(translation);
        this.rotation = new RotationImpl(new Vector3d(1, 0, 0), 0);
    }

    public SimpleAnimationImpl(final Vector3d rotation, final float angle) {
        this.translation = new TranslationImpl(new Vector3d(0, 0, 0));
        this.rotation = new RotationImpl(rotation, angle);
    }

    public static void changeSense() {
        SimpleAnimationImpl.sense = SimpleAnimationImpl.sense * (-1);
    }

    public static Vector3d getAnimationFunction() {
        return SimpleAnimationImpl.animationFunction;
    }

    public static void setAnimationFunction(final Vector3d animationFunction) {
        SimpleAnimationImpl.animationFunction = animationFunction;
    }

    public static void toggle() {
        SimpleAnimationImpl.canAnimation = !SimpleAnimationImpl.canAnimation;
    }

    public void addChild(final Node child) {
        this.translation.addChild(child);
    }

    public Iterator<Node> childIterator() {
        return this.translation.childIterator();
    }

    public void draw(final GLAutoDrawable gLDrawable) {
        this.translation.draw(gLDrawable);
    }

    public float getDistance() {
        return this.dist;
    }

    public float getSpeed() {
        return this.speed;
    }

    public void run() {
        if (SimpleAnimationImpl.canAnimation) {

            // speed
            if (Debug.ANIMATION_SPEED_UP) {
                this.speed += this.steps;
                if (this.speed > 1) {
                    this.speed = 1f;
                }
            }
            else if (Debug.ANIMATION_SPEED_DOWN) {
                this.speed -= this.steps;
                if (this.speed < 0) {
                    this.speed = 0;
                }
            }

            // translation
            this.angle = this.angle + this.speed * SimpleAnimationImpl.sense;
            if (this.angle > 360) {
                this.angle = 0;
            }
            final Vector3d tr = this.translation.getTranslation();
            SimpleAnimationImpl.animationFunction = new Vector3d(
                    (float) Math.sin(this.angle) * this.dist, tr.get(1),
                    -(float) Math.cos(this.angle) * this.dist);

            // translation
            this.translation.setTranslation(SimpleAnimationImpl.animationFunction);

            // rotation
            this.rotation.setAngle(this.rotation.getAngle() + 1);
        }
        else {
            SimpleAnimationImpl.animationFunction = new Vector3d(0, 0, 0);
        }
    }

    public void setDistance(final float distance) {
        this.dist = distance;
    }

    public void setRotation(final Vector3d rotation, final float angle) {
        this.rotation.setAxis(rotation);
        this.rotation.setAngle(angle);
    }

    public void setSpeed(final float speed) {
        this.speed = speed;
    }
}
